﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using AWS.SLAM.Configuration;
using AWS.SLAM.Data;
using AWS.SLAM.Events;
using AWS.SLAM.Hierarchy.Data;
using AWS.SLAM.Logging;
using AWS.SLAM.SharePoint;
using Microsoft.SharePoint;
using System.Text.RegularExpressions;

namespace AWS.SLAM.Hierarchy
{
	/// <summary>
	/// HierarchicalContentTypeItemCreator adds an item to SLAM's datasource(s) when a new List Item 
	/// configured to be managed by SLAM according to its Content Type is added in SharePoint then
	/// establishes its initial position in the hierarchy of items also managed by SLAM.  
	/// 
	/// A Content Type in SharePoint configured to use the HierarchicalContentTypeCreator requires that it contain
	/// a field of type HierarchyPositionField.
	/// </summary>
	public class HierarchicalContentTypeItemCreator : ContentTypeItemCreator
	{
		#region Private State

		/// <summary>
		/// SLAM Data service layer
		/// </summary>
		private IDataServices _dataServices;

		/// <summary>
		/// SLAM Configuration
		/// </summary>
		private IConfigurationManager _configuration;

		/// <summary>
		/// SLAM Logger
		/// </summary>
		private ILogger _logger;

		#endregion

		#region Constructors

		/// <summary>
		/// Creates instance of HierarchicalContentTypeItemCreator for the given 
		/// DataServices, Configuration, and Logger.
		/// </summary>
		/// <param name="dataServices"></param>
		/// <param name="configuration"></param>
		/// <param name="logger"></param>
		public HierarchicalContentTypeItemCreator(IDataServices dataServices, IConfigurationManager configuration, ILogger logger)
			: base(dataServices, configuration, logger)
		{
			_dataServices = dataServices;
			_configuration = configuration;
			_logger = logger;
		}

		#endregion

		/// <summary>
		/// Adds a new item to SLAM's external datasource then uses the value of the HierarchyPositionField
		/// that must be present in the given listItem to insert the item into the hierarchy
		/// managed by SLAM for the List Item's Content Type.
		/// </summary>
		/// <param name="listItem"></param>
		/// <returns></returns>
		public override bool Create(SPListItem listItem)
		{
			//Execute default SLAM Create process for a configured Content Type
			bool createResult = base.Create(listItem);

			string typeName = SlamItemContext.TypeName;

			//Open Hierarchy's DataService with the Default ConnectionString and DataSchema.
			//This process assumes the Hierarchy is saved in a SQL Server database and is using
			//a SLAM XML Configuration file.
			DataService dataService = new DataService(_configuration.GetSection<ConnectionStringSection>("ConnectionStrings").Default, 
				((XmlSqlDataMapping)_configuration.DataMapping).GetDataSchema());

			//Check configuration for the presence of a TableName for the listItem's
			//ContentType.  If it is present, use it as the item's typeName instead of the
			//ContentType Name.  Otherwise if it is not present use the ContentType's Name
			string itemTypeName = _configuration.DataMapping.GetTypeAttribute("", typeName, "TableName");
			if (String.IsNullOrEmpty(itemTypeName))
			{
				itemTypeName = typeName;
			}

			//For this type, add the Hierarchy "Left", "Right", and "Hierarchy Level" columns
			//in the SLAM table if they do not exist.
			dataService.AddHierarchyColumns(itemTypeName);

			TypeIdDefinition typeIdDefinition = new TypeIdDefinition();
			string typeIdDefinitionName = _configuration.DataMapping.GetTypeAttribute("", typeName, "TypeIdDefinition");
			if (String.IsNullOrEmpty(typeIdDefinitionName))
			{
				typeIdDefinitionName = ((XmlSqlDataMapping)_configuration.DataMapping).GetTypeIdDefinitionName();
			}
			TypeIdDefinitionSection typeIdDefininitionSection = _configuration.GetSection<TypeIdDefinitionSection>("TypeIdDefinitions");

			if (String.IsNullOrEmpty(typeIdDefinitionName))
			{
				typeIdDefinition = typeIdDefininitionSection.Default;
			}
			else
			{
				typeIdDefinition = typeIdDefininitionSection.GetTypeIdDefinition(typeIdDefinitionName);
			}

			string idColumnName = Regex.Replace(String.IsNullOrEmpty(typeIdDefinition.NameFormat) ? "ID" : typeIdDefinition.NameFormat.Replace("{TypeName}", _configuration.DataMapping.GetTypeAttribute("", typeName, "Name")).Replace("{TableName}", itemTypeName), "[\\W\\s]", "");

			//Get the Hierarchy Position Field's value from the listItem regardless of its name
			string hierarchyPositionFieldValue = listItem.GetHierarchyPositionFieldValue();

			if (!String.IsNullOrEmpty(hierarchyPositionFieldValue))
			{
				//The Hierarchy Position Field's value has at least 2 parts, the first
				//part contains a Parent GUID Id, the second part contains a sibling
				//ListItem GUID Id.  
				string[] fieldValueParts = hierarchyPositionFieldValue.Split('|');
				if (fieldValueParts.Length >= 2 && !String.IsNullOrEmpty(fieldValueParts[0]))
				{
					//If the first part is an Empty Guid then this listItem is a root node. Otherwise
					//add as a child node
					if (fieldValueParts[0] != Guid.Empty.ToString())
					{
						//If the second part is an Empty Guid then this listItem goes at the end
						//of the parent's children, otherwise it goes to the left, in place, of the
						//sibling defined by fieldValuesParts[1]
						if (!String.IsNullOrEmpty(fieldValueParts[1]) && fieldValueParts[1] != Guid.Empty.ToString())
						{
							dataService.AddAsLeftSiblingNode(itemTypeName, idColumnName, fieldValueParts[1], Convert.ToString(listItem.GetUniqueId()));
						}
						else
						{
							dataService.AddAsLastChildNode(itemTypeName, idColumnName, fieldValueParts[0], Convert.ToString(listItem.GetUniqueId()));
						}
					}
					else
					{
						dataService.AddAsRootNode(itemTypeName, idColumnName, Convert.ToString(listItem.GetUniqueId()));
					}

					dataService.RecalculateHierarchyLevels(itemTypeName, idColumnName);
				}
			}
			return createResult;
		}
	}
}
